#include "wl_malloc.h"

#include "tinyalloc.h"
#include "wl_mutex.h"
#include "wl_trace.h"

#ifdef __cplusplus
extern "C" {
#endif

typedef struct {
    wl_bool  initialized;
    WL_MUTEX mutex;
} wl_mem_global;

wl_mem_global s_mem_global;

wl_bool wl_mem_init(const void*   base,
                    const void*   limit,
                    const wl_size heap_blocks,
                    const wl_size split_thresh,
                    const wl_size alignment) {
    if (!s_mem_global.initialized) {
        if (!ta_init(base, limit, heap_blocks, split_thresh, alignment)) {
            WLLOGW("ta_init fail");
            return wl_false;
        }
        if (0 != wl_mutex_create("malloc", &s_mem_global.mutex)) {
            WLLOGW("wl_mutex_create fail");
            return wl_false;
        }
        s_mem_global.initialized = wl_true;
        return wl_true;
    } else {
        WLLOGW("memory pool has init");
        return wl_false;
    }
}

void* wl_mem_calloc(wl_size nmemb, wl_size size) {
    void* ptr = wl_null;
    wl_mutex_acquire(&s_mem_global.mutex);
    ptr = ta_calloc(nmemb, size);
    wl_mutex_release(&s_mem_global.mutex);
    return ptr;
}

void* wl_mem_malloc(wl_size size) {
    void* ptr = wl_null;
    wl_mutex_acquire(&s_mem_global.mutex);
    ptr = ta_alloc(size);
    wl_mutex_release(&s_mem_global.mutex);
    return ptr;
}

void wl_mem_free(void* ptr) {
    wl_mutex_acquire(&s_mem_global.mutex);
    ta_free(ptr);
    wl_mutex_release(&s_mem_global.mutex);
}

void* wl_mem_realloc(void* ptr, wl_size size) {
    void* new_ptr = wl_null;
    wl_mutex_acquire(&s_mem_global.mutex);
    new_ptr = ta_alloc(size);
    if (new_ptr) {
        wl_size ptr_size = ta_mem_size(ptr);
        memset(new_ptr, 0, size);
        if (ptr_size) {
            memcpy(new_ptr, ptr, ptr_size);
        }
    }
    ta_free(ptr);
    wl_mutex_release(&s_mem_global.mutex);
    return new_ptr;
}

wl_size wl_mem_size(void* ptr) {
    wl_size size = 0;
    wl_mutex_acquire(&s_mem_global.mutex);
    size = ta_mem_size(ptr);
    wl_mutex_release(&s_mem_global.mutex);
    return size;
}

wl_size wl_mem_num_free(void) {
    wl_size size = 0;
    wl_mutex_acquire(&s_mem_global.mutex);
    size = ta_num_free();
    wl_mutex_release(&s_mem_global.mutex);
    return size;
}

wl_size wl_mem_num_used(void) {
    wl_size size = 0;
    wl_mutex_acquire(&s_mem_global.mutex);
    size = ta_num_used();
    wl_mutex_release(&s_mem_global.mutex);
    return size;
}

wl_size wl_mem_num_fresh(void) {
    wl_size size = 0;
    wl_mutex_acquire(&s_mem_global.mutex);
    size = ta_num_fresh();
    wl_mutex_release(&s_mem_global.mutex);
    return size;
}

wl_bool wl_mem_check(void) {
    wl_bool ret = wl_false;
    wl_mutex_acquire(&s_mem_global.mutex);
    ret = ta_check();
    wl_mutex_release(&s_mem_global.mutex);
    return ret;
}

#ifdef __cplusplus
}
#endif
